/* NOTICE
 
    Jim - the Java Image Manager, copyright (c) 2005 - 2007 Grant Gardner 
 
    Jim is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Jim is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  
    In addition, as a special exception, you are permitted to link this code
    with the 3rd party libraries required to compile this file and to
    distribute a linked combination including them. You must obey the
    GNU General Public License in all respects for all of the code except for
    those 3rd party libraries that are licenced under terms incompatible with the
    GNU General Public License.  
 
 
 NOTICE */

/*
 * Created on 17/11/2004
 *  
 */

package au.com.lastweekend.jim.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import au.com.lastweekend.jim.swing.folderchooser.ToolBarFolderChooser;

/**
 * 
 * @author grant@lastweekend.com.au
 * @version $Id: SwingUtil.java,v 1.6 2006/02/19 06:04:55 ggardner Exp $
 */
public final class SwingUtil {

    private static final Logger LOG = Logger.getLogger(SwingUtil.class);
    private static final String[] ICON_PATHS = {"", "/com/famfamfam/silk/", "/images/"};
    public static final String TOOLBAR_SEPARATOR = "TOOLBAR_SEP";
    public static final String TOOLBAR_FOLDERLIST = "TOOLBAR_FOLDERLIST";
    public static final String TOOLBAR = "TOOLBAR";
    public static final String MENU_SEPARATOR = "MENU_SEP";
    public static final String MENU = "MENU";
    public static final String POPUP = "POPUP";
    public static final String POPUP_SEPARATOR = "POPUP_SEP";

    private SwingUtil() {

        // hidden utility constructor
    }

    public static void debugMemory(Logger log) {

        if (log.isDebugEnabled()) {
            long maxMemory = Runtime.getRuntime().maxMemory();
            long totalMemory = Runtime.getRuntime().totalMemory();
            long freeMemory = Runtime.getRuntime().freeMemory();
            log.debug("Free memory (Mb) = " + (freeMemory + maxMemory - totalMemory) / (1024 * 1024));
        }
    }

    public static ImageIcon createImageIcon(String path) {

        return createImageIcon(path, path);

    }

    public static void debugActionMap(JComponent component, Logger log) {

        if (log.isDebugEnabled()) {
            log.debug("ActionMap for " + component);
            KeyStroke[] allKeys = component.getInputMap().allKeys();
            if (allKeys == null) {
                log.debug("No input keys");
            } else {
                for (int i = 0; i < allKeys.length; i++) {
                    log.debug("Input: " + allKeys[i] + "\t" + component.getInputMap().get(allKeys[i]));

                }
            }
            Object[] allKeys2 = component.getActionMap().allKeys();
            if (allKeys2 == null) {
                log.debug("No action keys");
            } else {
                for (int i = 0; i < allKeys2.length; i++) {
                    log.debug("Action: " + allKeys2[i] + "\t" + component.getActionMap().get(allKeys2[i]));

                }
            }
        }
    }

    public static void bindKeyAction(JComponent comp, Action a) {

        comp.getActionMap().put(a.getValue(Action.NAME), a);

    }

    public static void bindKeyAction(JComponent comp, String keyName, Action a) {

        KeyStroke keyStroke = KeyStroke.getKeyStroke(keyName);

        comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keyStroke, a.getValue(Action.NAME));
        bindKeyAction(comp, a);

    }

    public static JRadioButton createRadioButton(String name, ButtonGroup buttonGroup, ActionListener actionListener) {

        JRadioButton rb = new JRadioButton(name);
        rb.setActionCommand(name);
        buttonGroup.add(rb);
        if (actionListener != null) {
            rb.addActionListener(actionListener);
        }
        return rb;

    }

    public static void printSizes(Component c, Logger log) {

        String compName = c.getName();
        if (compName == null) {
            compName = c.getClass().getName();
        }
        log.info(compName + "- Curr: " + prettyDimension(c.getSize()) + " Pref: " + prettyDimension(c.getPreferredSize())
                + " Min: " + prettyDimension(c.getMinimumSize()) + " Max: " + prettyDimension(c.getMaximumSize()));
    }

    public static String prettyDimension(Dimension d) {

        return ("[w=" + d.width + ",h=" + d.height + "]");
    }

    /**
     * Show a component in a frame. Useful for testing.
     * 
     * @param name
     * @param contentPane
     */
    public static void createAndShowGUI(String name, JComponent contentPane) {

        // Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        // Create and set up the window.
        JFrame frame = new JFrame(name);

        frame.setContentPane(contentPane);

        // Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void setActionParameters(Action a, String iconPath, String shortDesc, String longDesc) {

        if (shortDesc == null)
            shortDesc = (String) a.getValue(Action.NAME);
        if (longDesc == null)
            longDesc = shortDesc;

        if (iconPath != null) {
            ImageIcon imageIcon = createImageIcon(iconPath, longDesc);
            a.putValue(Action.SMALL_ICON, imageIcon);
        }
        a.putValue(Action.SHORT_DESCRIPTION, shortDesc);
        a.putValue(Action.LONG_DESCRIPTION, longDesc);
    }

    public static void scaleActionIcon(Action a, int maxSize) {

        ImageIcon i = (ImageIcon) a.getValue(Action.SMALL_ICON);

        if (i != null && i.getIconHeight() > maxSize) {
            i = new ImageIcon(i.getImage().getScaledInstance(-1, maxSize, Image.SCALE_DEFAULT));
            a.putValue(Action.SMALL_ICON, i);
        }
    }

    private static ImageIcon createImageIcon(String path, String desc) {

        java.net.URL imgURL = null;
        ImageIcon imageIcon = null;
        if (path.startsWith("/")) {
            imageIcon = new ImageIcon(path, desc);
        } else {
            for (int i = 0; i < ICON_PATHS.length; i++) {
                imgURL = SwingUtil.class.getResource(ICON_PATHS[i] + path);
                if (imgURL != null) {
                    imageIcon = new ImageIcon(imgURL, desc);
                }
            }
        }

        if (imageIcon == null) {
            LOG.info("Can't find icon " + path);
        }
        return imageIcon;

    }

    /**
     * @param node
     * @return
     */
    public static TreePath getTreePath(TreeNode node) {

        return new TreePath(getPathToRoot(node, 0));
    }

    /**
     * @param object
     * @param node
     * @return
     */
    public static TreeNode[] getPathToRoot(TreeNode node, int depth) {

        TreeNode[] result;
        if (node == null) {
            result = new TreeNode[depth];
        } else {
            depth++;
            result = getPathToRoot(node.getParent(), depth);
            result[result.length - depth] = node;
        }

        return result;
    }

    public static JToolBar createToolBar(Collection<Action> actions, ToolBarFolderChooser toolBarFolderChooser) {

        JToolBar toolBar = new JToolBar();
        toolBar.setFont(toolBar.getFont().deriveFont((float) 8));

        for (Action action : actions) {
            if (action.getValue(SwingUtil.TOOLBAR) != null) {
                JButton button = new JButton(action);
                button.setText(null);
                button.setPreferredSize(new Dimension(20, 20));
                toolBar.add(button);

                if (action.getValue(SwingUtil.TOOLBAR_SEPARATOR) != null) {
                    toolBar.addSeparator();
                }

                if (action.getValue(SwingUtil.TOOLBAR_FOLDERLIST) != null) {
                    toolBar.add(toolBarFolderChooser.getFolderList());
                }
            }
        }

        return toolBar;
    };

    public static JMenuBar createMenuBar(Collection<Action> actions) {

        JMenuBar menuBar = new JMenuBar();

        Map<String, JMenu> menuMap = new HashMap<String, JMenu>();

        for (Action action : actions) {

            Object value = action.getValue(SwingUtil.MENU);
            if (value != null && value instanceof String) {
                String menuName = (String) value;
                String[] menuNames = menuName.split(":");
                String thisMenu = "";
                JComponent parentComponent = menuBar;
                for (String subMenuName : menuNames) {
                    thisMenu = thisMenu + subMenuName;
                    if (!menuMap.containsKey(thisMenu)) {
                        JMenu newMenu = new JMenu(subMenuName);
                        menuMap.put(thisMenu, newMenu);
                        parentComponent.add(newMenu);
                        LOG.debug("Created menu " + subMenuName);
                    }
                    parentComponent = menuMap.get(thisMenu);
                    thisMenu = thisMenu + ":";
                }
                JMenu menu = menuMap.get(menuName);
                if (action instanceof PropertyBoundToggleAction) {
                    menu.add(new PropertyBoundCheckBoxMenuItem((PropertyBoundToggleAction) action));
                } else {
                    menu.add(action);
                }
                if (action.getValue(SwingUtil.MENU_SEPARATOR) != null) {
                    menu.addSeparator();
                }
            }
        }

        return menuBar;
    }

    /**
     * @param actions
     * @return
     */
    public static JPopupMenu createPopupMenu(Collection<Action> actions) {

        JPopupMenu popupMenu = new JPopupMenu();
        for (Action action : actions) {
            if (action.getValue(POPUP) != null) {
                popupMenu.add(action);
            }
            if (action.getValue(POPUP_SEPARATOR) != null) {
                popupMenu.addSeparator();
            }
        }
        return popupMenu;
    }

}